package org.fuys.coder.domain.act.lottery.service.strategy.factory;

import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.domain.act.lottery.model.vo.strategy.LotteryStrategyRateMap;
import org.fuys.coder.domain.act.lottery.model.vo.strategy.LotteryStrategyVO;
import org.fuys.coder.domain.act.lottery.model.vo.strategy.LotteryStrategyDetailVO;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static org.fuys.coder.domain.act.lottery.model.vo.strategy.LotteryStrategyRateMap.RATE_TUPLE_LENGTH;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.lottery.service.strategy.factory
 * @className: LotteryStrategyFactory
 * @author: WangJing
 * @description: 抽奖策略的简单工厂模式
 * @date: 2024/7/5 23:45
 * @version: 1.0
 */

public class LotteryStrategyFactory {
    //对于key的pair 左是适合的数量 右边是模式
    private static final Map<Pair<Integer,Integer>, List<Pair<Integer, Double>>> typeOddsInfo
            =new ConcurrentHashMap<>();
    private static final Map<LotteryStrategyVO,List<Pair<Integer, Double>>> showInfo
            =new ConcurrentHashMap<>();
    private static final Map<Integer,LotteryStrategyVO> strategyIdMap
            =new ConcurrentHashMap<>();


    public static void initFactory(List<Pair<LotteryStrategyVO, LotteryStrategyDetailVO>> info){
        //左边是策略信息 右边是策略具体的概率
        if(!ObjectUtils.isEmpty(info)) {
            info.forEach(pair -> {
                final LotteryStrategyVO strategyVO = pair.getLeft();
                final LotteryStrategyDetailVO detailVO = pair.getRight();
                strategyIdMap.put(strategyVO.getId(),strategyVO);
                //分成适合数量以及策略模式作为key
                final Pair<Integer, Integer> typeStrategy = new Pair<>();
                //分成各个具体概率
                final Pair<Integer, Double> oddsStrategy = new Pair<>();
                typeStrategy.setLeft(strategyVO.getSuitNum());
                typeStrategy.setRight(strategyVO.getStrategyMode());
                oddsStrategy.setLeft(detailVO.getPosition());
                oddsStrategy.setRight(detailVO.getWeight().doubleValue());
                //神金 不这样写怎么写呢？ 难道这样还能抽象成函数吗
                if (typeOddsInfo.containsKey(typeStrategy)) {
                    typeOddsInfo.get(typeStrategy).add(oddsStrategy);
                } else {
                    List<Pair<Integer, Double>> list = new ArrayList<>();
                    list.add(oddsStrategy);
                    typeOddsInfo.put(typeStrategy, list);
                }
                if (showInfo.containsKey(strategyVO)) {
                    showInfo.get(strategyVO).add(oddsStrategy);
                } else {
                    List<Pair<Integer, Double>> list = new ArrayList<>();
                    list.add(oddsStrategy);
                    showInfo.put(strategyVO, list);
                }
            });
            sortInfo();
            initRateMap();
        }
    }

    public static List<Pair<Integer,Double>> getStrategyOddInfo(Integer awardNum,Integer strategyMode){
        return typeOddsInfo.get(new Pair<>(awardNum,strategyMode));
    }

    private static void sortInfo(){
        typeOddsInfo.forEach((pair,list)->{
            list.sort(Comparator.comparingInt(Pair::getLeft));
        });
        showInfo.forEach((strategyVO,list)->{
            list.sort(Comparator.comparingInt(Pair::getLeft));
        });
    }
    private static void initRateMap(){
        typeOddsInfo.forEach(LotteryStrategyFactory::transferRateMap);
    }

    public static void addTypeOddsInfo(Pair<Integer,Integer> type, List<Pair<Integer, BigDecimal>> odds) {
        //首先排序 根据序号排序
        final List<Pair<Integer, Double>> collect = odds.stream().map(pair -> {
            Pair<Integer, Double> newPair = new Pair<>();
            newPair.setLeft(pair.getLeft());
            newPair.setRight(pair.getRight().doubleValue());
            return newPair;
        }).sorted(Comparator.comparingInt(Pair::getLeft)).collect(Collectors.toList());
        typeOddsInfo.put(type,collect);
        transferRateMap(type, collect);
    }

    public static LotteryStrategyVO getStrategyById(Integer strategyId){
        return strategyIdMap.get(strategyId);
    }

    private static void transferRateMap(Pair<Integer, Integer> type, List<Pair<Integer, Double>> collect) {
        int cursorVal=0;
        List<Integer> rate=new ArrayList<>(Collections.nCopies(RATE_TUPLE_LENGTH, 0));
        for (Pair<Integer, Double> pair : collect) {
            int rateVal=(int)(pair.getRight()*100);
            for(int i=cursorVal+1;i<=(rateVal+cursorVal);i++){
                rate.set(LotteryStrategyRateMap.hashIdx(i),pair.getLeft());
            }
            cursorVal+=rateVal;
        }
        LotteryStrategyRateMap.setMapValue(type,rate);
    }

}
